package com.pingan.agentbank.aaos.service;

import com.pab.framework.foundation.MaskUtils;
import com.pingan.agentbank.aaos.exception.AAOSException;
import com.pingan.agentbank.aaos.pojo.*;
import com.pingan.agentbank.aaos.util.AaisRemote;
import com.pingan.agentbank.aaos.util.AcrsRemote;
import com.pingan.agentbank.aaos.util.FixedLenUtil;
import com.pingan.vframe.db.DBIterator;
import com.pingan.vframe.db.DBRecordHandler;
import com.pingan.vframe.db.DBTransaction;
import com.pingan.vframe.lang.Handler;
import com.pingan.vframe.lang.Inject;
import com.pingan.vframe.logging.Log;
import com.pingan.vframe.logging.LogFactory;
import com.pingan.vframe.sdo.ServiceData;
import com.pingan.vframe.util.JSON;
import com.pingan.vframe.util.JSONCaseType;

import java.io.*;
import java.util.*;


public class BusinessService {

    private final Log log = LogFactory.getLog();


    @Inject
    ApproFileDaoService approFileDaoService;
    @Inject
    ApproLineDaoService approLineDaoService;
    @Inject
    AaisRemote aaisRemote;
    @Inject
    AcrsRemote acrsRemote;







    /*
     * 正常执行：查询状态为1的File，循环处理——>更改状态为3——>处理——>更改状态为4
     */
    public void perform(Config config) {

        //0.找到状态为1的file
        log.info("[ AAOS ] " +config.getBank()+  " (BusinessModule) " + " check new data");
        DBIterator<ApproFileInfo> iterator = approFileDaoService.queryByState(1);
        if (!iterator.hasNext()) {
            log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "no data detected, task over");
            return;
        } else {
            log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "new data detected, task start");
        }
        List<ApproFileInfo> list = new ArrayList<>();
        while (iterator.hasNext()) {
            list.add(iterator.next());
        }

        //对状态为1的file进行循环处理
        for (ApproFileInfo approFileInfo : list) {

            DBTransaction tran = DBTransaction.get();
            //初始化变量：文件id、文件名、结论文件名、结论文件绝对路径
            long id = approFileInfo.getId();
            String fileName = approFileInfo.getFilename();
            String resultFileName = "RS-" + fileName;
            String desc = config.getDescDir() + "/" + "RS-" + fileName;

            //1.更改状态为3标识开始处理
            approFileDaoService.updateStateById(3, (int) id);
            log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + fileName + " change record state to 3, task start");


            //2.写入文件
            File descFile = new File(desc);
            if (descFile.exists()){
                descFile.delete();
            }
            try {
                //由此进入处理文件核心逻辑
                writeFile(id, config, desc,fileName);
            } catch (IOException e) {
                log.error(e.getMessage());
                throw new AAOSException(e.getMessage());
            }
            log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + fileName + " write file over");


            //3.写入.ok标识完成
            String ok = desc.substring(0, desc.lastIndexOf(".")) + ".ok";
            File file = new File(ok);
            if (file.exists()){
                file.delete();
            }
            try {
                file.createNewFile();
            } catch (IOException e) {
                log.error(e.getMessage());
                throw new AAOSException(e.getMessage());
            }
            log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + fileName + " write okfile over");

            //4.更改状态为4标识处理结束
            approFileDaoService.updateResultNameAndStateById(resultFileName, 4, (int) id);
            //一个文件对应的记录量可能非常大，处理完一个文件提交一次事务
            tran.commitAndResume();
            log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + fileName + " change record state to 4,task over");

        }
        log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + " task over");
    }


    /*
     * 中断任务继续执行：查询状态为3的File——>处理——>更改状态为4
     */
    public void resume(Config config) {

        //0.找到状态为3的file
        log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "-resume-" + " check interrupted task");
        DBIterator<ApproFileInfo> iterator = approFileDaoService.queryByState(3);

        if (!iterator.hasNext()) {
            log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "-resume-" + " no interrupted task detected, task over");
            return;
        } else {
            log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "-resume-" + " interrupted task detected, task start");
        }

        List<ApproFileInfo> list = new ArrayList<>();
        while (iterator.hasNext()) {
            list.add(iterator.next());
        }

        //对状态为1的file进行循环处理
        for (ApproFileInfo approFileInfo : list) {
            DBTransaction tran = DBTransaction.get();
            //初始化变量 文件id、文件名、结果文件名、文件绝对路径
            Long id = approFileInfo.getId();
            String fileName = approFileInfo.getFilename();
            String resultFileName = "RS-" + fileName;
            String desc = config.getDescDir() + "/" + resultFileName;

            //1.写入文件
            File descFile = new File(desc);
            if (descFile.exists()){
                descFile.delete();
            }
            try {
                writeFile(id, config, desc,fileName);
            } catch (IOException e) {
                log.error("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "-resume-" + fileName + " write file error",e);
                throw new AAOSException("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "-resume-" + fileName + " write file error",e);
            }
            log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "-resume-" + fileName + " write file over");

            //2.写入.ok标识完成
            String ok = desc.substring(0, desc.lastIndexOf(".")) + ".ok";
            File file = new File(ok);
            try {
                file.createNewFile();
            } catch (IOException e) {
                log.error("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "-resume-" + fileName + " write okfile error",e);
                throw new AAOSException("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "-resume-" + fileName + " write okfile error",e);
            }
            log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "-resume-" + fileName + " write okfile over");


            //3.更改状态为4标识处理结束
            approFileDaoService.updateResultNameAndStateById(resultFileName, 4, (int) approFileInfo.getId());
            //一个文件对应的记录量可能非常大，处理完一个文件提交一次事务
            tran.commitAndResume();
            log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "-resume-" + fileName + " change record state to 4,task over");

        }
        log.info("[ AAOS ] " +config.getBank()+ " (BusinessModule) " + "-resume-" + " task over");
    }

    /*
    * 根据文件id查出文件，并将其中行转换为行方结论文件
    * 参数：fileId 文件id    config 配置   descFilePath 目标文件位置    fileName 文件名
    * fileName用于错误日志打印时定位到文件
    **/
    private void writeFile(long fileId, Config config, String descFilePath,String fileName) throws IOException {

        DBIterator<ApproLineInfo> lineIterator = approLineDaoService.queryByFileId(fileId);
        List<ApproLineInfo> idList = new ArrayList<>();
        while (lineIterator.hasNext()){
            idList.add(lineIterator.next());
        }

        String aaisFieldsPath = config.getFieldsDir()+"/aais-"+fileName;
        File file = new File(aaisFieldsPath);
        if (file.exists()){
            file.delete();
        }
        OutputStream aaisFieldsOutputStream = new FileOutputStream(aaisFieldsPath,true);

        OutputStream outputStream = new FileOutputStream(descFilePath, true);
        Map<String,String> map = new HashMap<>();


        //循环写入文件
        for (int i=0;i<idList.size();i++){

            ApproLineInfo approLineInfo = idList.get(i);
            //将审批结论文件加工成行方结论文件
            lineHandler(map,approLineInfo, config,fileName,i+1);
            String string = map.get("result") + config.getLineSeparator();
            if (i == idList.size()-1){
                if (!config.getEndLineEmpty().equals("true")){
                    string = string.substring(0,string.length()-1);
                }
            }

            String fields = "aais-->"+map.get("aais")+","+"acrs-->outAppNo:"+map.get("outAppNo")+ config.getLineSeparator();
            try {
                aaisFieldsOutputStream.write(fields.getBytes(config.getDescCode()));
                outputStream.write(string.getBytes(config.getDescCode()));
            } catch (IOException e) {
                log.error(e.getMessage());
                throw new AAOSException(e.getMessage());
            }
        }

        aaisFieldsOutputStream.flush();
        aaisFieldsOutputStream.close();
        outputStream.flush();
        outputStream.close();
        File aaisOkFile = new File(aaisFieldsPath.substring(0,aaisFieldsPath.lastIndexOf("."))+".ok");
        aaisOkFile.createNewFile();
    }

    /*
     *  将ApproLineInfo转换为行方结论文件
     *  参数：lineInfos 审批结论文件行  config 配置    fileName 文件名  count 文件行 用于定位问题所在位置
     *  返回值：行方结论文件行
     */
    private void lineHandler(Map<String,String> map,ApproLineInfo lineInfos,Config config,String fileName,int count) {


        String identityNo = MaskUtils.maskIdentityNo(lineInfos.getGlobal_id());
        String mobile = MaskUtils.maskMobileNo(lineInfos.getMobile());
        String approMsg = "[application_no:"+lineInfos.getApplication_no()+",chinese_name:"+lineInfos.getChinese_name()+",mobile:"+mobile+",global_id:"+identityNo+"]";
        //根据配置文件读取请求参数，拿网申字段
        //进件编号从ApproLineInfo中获取
        //补充sysheader
        ServiceData sourServiceData = new ServiceData();

        RequestInfo requestInfo = config.getRequestInfo();
        String appId = requestInfo.getSysHeader().getAppId();
        String orgCode = requestInfo.getSysHeader().getOrgCode();
        SysHeader sysHeader = new SysHeader(String.valueOf(new Date().getTime()), appId, UUID.randomUUID().toString().replace("-", ""), orgCode);

        List<String> params = config.getRequestInfo().getBusiData().getQueryPara();
        //如果调用AAIS的配置是开启的，并且查询字段数量大于0
        //从发卡接入平台调用字段，并放入serviceData
        if ("true".equals(config.getAaisRemoteCall())&&params.size()>0){


            String queryType = requestInfo.getBusiData().getQueryType();
            List<String> queryPara = requestInfo.getBusiData().getQueryPara();

            BusiData busiData = new BusiData(queryType, lineInfos.getApplication_no(), queryPara);
            RequestInfo requestInfoNew = new RequestInfo(sysHeader, busiData);

            try {
                sourServiceData = aaisRemote.getApplyInfoFromAAIS(requestInfoNew);
            } catch (Exception e){
                //记录哪个文件哪一行报错
                log.error("[ AAOS ] "+config.getBank()+" (BusinessModule) "+fileName+" row "+ count+" AAIS Remote Call ERROR",e);
                throw new AAOSException("[ AAOS ] "+config.getBank()+" (BusinessModule) "+fileName+" row "+ count+" AAIS Remote Call ERROR",e);
            }

            //取出返回码信息
            String responseCode = sourServiceData.getString("responseCode");

            if (!"0".equals(responseCode)){
                //TODO
                //记录哪个文件哪一行报错
                log.error("[ AAOS ] "+config.getBank()+" (BusinessModule) "+fileName+" row "+ count+" AAIS Fileds Query ERROR");
                throw new AAOSException("[ AAOS ] "+config.getBank()+" (BusinessModule) "+fileName+" row "+ count+" AAIS Fileds Query ERROR");
            }
            //返回码正常，取出busiData信息
            sourServiceData = sourServiceData.getServiceData("busiData");

            map.put("aais",sourServiceData.toString().replace("\n","").replace(" ",""));
            //System.err.println(sourServiceData.toString().replace("\n","").replace(" ",""));
            List<String> strList = new ArrayList<>();

            //校验从AAIS调用的字段是否为空
            for (String key:config.getAaisFileds()){
                if (FixedLenUtil.isBlank(sourServiceData.getString(key))){
                    strList.add(key);

                }
            }
            if (strList.size()>0){
                StringBuffer str = new StringBuffer();
                for (String temp:strList){
                    str.append(temp);
                    str.append(",");
                }
                String fields = str.substring(0,str.length()-1);
                log.error("[ AAOS ] "+"FieldEmptyError"+" (BusinessModule) "+fileName+" row "+ count+" AAIS Remote Call ERROR, fileds:{"+fields+"} is empty "+approMsg);
                throw new AAOSException("[ AAOS ] "+"FieldEmptyError"+" (BusinessModule) "+fileName+" row "+ count+" AAIS Remote Call ERROR, filed:{"+fields+"} is empty "+approMsg);
            }

        }

        //从征信平台调用字段，并放入serviceData
        if ("true".equals(config.getAcrsRemoteCall())){
            BusiData busiData = new BusiData();
            busiData.setApplicationNo(lineInfos.getApplication_no());
            RequestInfo requestInfoNew = new RequestInfo(sysHeader, busiData);

            ServiceData acrsServiceData = new ServiceData();
            try {
                acrsServiceData = acrsRemote.getApplyInfoFromACRS(requestInfoNew);
            } catch (Exception e){

            }

            //取出返回码信息
            String responseCode = acrsServiceData.getString("responseCode");
            String outAppNo = "";
            //如果返回码为0，则取出outAppNo，如果返回码不为0，则outAppNo赋值为空
            if ("0".equals(responseCode)){
                outAppNo = acrsServiceData.getServiceData("busiData").getString("outAppNo");
                map.put("acrs",outAppNo);
                System.err.println(outAppNo);
            }
            sourServiceData.putString("outAppNo",outAppNo);
        }


        //ApproLineInfo-->ServiceData 将ApproLineInfo信息转化后放入ServiceData
        ServiceData serviceData = new ServiceData();
        serviceData = config.getLineHandler().toServiceData(lineInfos,sourServiceData,serviceData);
        //ServiceData-->银数定长
        String result = config.getLineHandler().toResultString(approMsg,fileName,count,serviceData,config);
        map.put("result",result);
    }



}
